同步 Sync 與非同步 Async


Posted by Erica on 2021-04-08

同步與非同步的差異

在學習同步與非同步的概念時很容易混淆,「同步」光看字面上的意思,可能會誤解成「所有動作同時進行」,而其實正好相反。
就以去夜市點餐來說明,如果今天想買的東西有:雞排、QQ球、珍奶。

  • 同步 (sync):先去買雞排 -> 再去買QQ球 -> 然後再買珍奶。
    像這樣「先完成 A 才能做 B、C、D ...」的運作方式我們就會把它稱作「同步」。

  • 非同步 (async):再找兩個朋友幫忙,每人去一個攤位買一樣東西,就可以同時買好雞排、QQ球、珍奶。

所以同步的概念其實比較像是「一步一步來處理」的意思。
非同步則是,我不用等待 A 做完才做 B、C,而是這三個事情可以同時發送出去。

Promise

Promise 是 ES6 新增的建構函式,用來優化非同步的語法,增加可讀性。
Promise 字面上翻譯就是「約定、承諾」,可以想像成 A 和 B 約定要做某件事情,接著回報處理結果,而這個結果只能是「完成」或「拒絕」。

function asyncFunction (value) {
    return new Promise((resolve, rejecte) => {
        value ? resolve('處理完成的結果') : reject('被拒絕的原因')
    })
}

為什麼需要 Promise?

JavaScript 是單執行緒(同步)的程式語言,一次只能處理一件事情,所以遇到非同步的事件時,就會先把程式碼放到「事件佇列」,等到所有事件處理完後才會執行非同步事件。

console.log('開始') // 執行順序 1

setTimeout(() => {
  console.log('非同步事件') // 執行順序 3
}, 0)

console.log('程式碼結束') // 執行順序 2

狀態

Promise 在處理非同步的事件的過程中,包含不同的進度狀態

  • Pending:尚未得到結果
  • Resolved:事件已經執行完畢且成功操作,回傳 resolve 的結果
  • Rejected:事件已經執行完畢但操作失敗,回傳 reject 的結果

接收回傳

Promise 可以用 thencatch 來接收並回傳結果:
then 可以同時接收成功、失敗結果,而 catch 只接收失敗結果

  • 使用 catch 接收失敗:
    在任何階段遇到 reject 時,都會直接跳到 catch,之後的 then 都不會執行
    雖然 catch 依然可以使用 return 繼續串接,但很少這樣使用
promise(1)
    .then(success => {
        console.log(success) // resolve 接收成功 // '1'
        return promise(0)    // return promise(0) -> reject 跳到 catch
    })

    .then(success => {       // 因為上面出現 reject 所以跳過
        console.log(success)
        return promise(3)
    })

    .catch( fail => {
        console.log(fail)    // reject 接收失敗 // '失敗'
    })
  • 使用 then 接收失敗:
    then 中的兩個函式必定執行其中一個,可以用此方式確保所有的鏈接都能夠被執行
promise(0)
    .then(success => {
        console.log(success)
        return promise(1)
    }, fail => {
        console.log(fail)     // reject 接收失敗 // '失敗'
        return promise(2)     // return promise(2)
    })

    .then(success => {
        console.log(success) // resolve 接收成功 // '2'
        return promise(0)    // return promise(0)
    }, fail => {
        console.log(fail)
        return promise(4)
    })

    .then(success => {
        console.log(success)
    }, fail => {
        console.log(fail)     // reject 接收失敗 // '失敗'
    })

完成

  • 最後可以使用 finally 來確認工作結束
  • finally 不帶有任何參數,適合用來確認 Ajax 已經讀取完成
promise(1)
    .then(success => {
        console.log(success)
    }).finally(() => {
        console.log('done')
    })

參考文章:


#javascript







Related Posts

HTML CSS position 屬性

HTML CSS position 屬性

1731. The Number of Employees Which Report to Each Employee

1731. The Number of Employees Which Report to Each Employee

體驗最新的 JS 語法:Babel

體驗最新的 JS 語法:Babel


Comments